import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

public class Tetris extends JPanel implements ActionListener, KeyListener {
    private static final int WIDTH = 10;
    private static final int HEIGHT = 20;
    private static final int TILE_SIZE = 30;
    private static final int FPS = 60;
    private static final int DELAY = 1000 / FPS;

    private final Timer timer;
    private final Random random = new Random();
    private final Color[] colors = {
            new Color(0, 0, 0),       // 黑色（背景）
            new Color(255, 0, 0),     // 红色
            new Color(0, 255, 0),    // 绿色
            new Color(0, 0, 255),    // 蓝色
            new Color(255, 255, 0),   // 黄色
            new Color(255, 0, 255),   // 紫色
            new Color(0, 255, 255),   // 青色
            new Color(255, 165, 0)   // 橙色
    };

    private int[][] grid = new int[HEIGHT][WIDTH];
    private int[][] currentShape;
    private int currentX, currentY;
    private int currentColor;

    private final int[][][] SHAPES = {
            {{1, 1, 1, 1}}, // I
            {{1, 1}, {1, 1}}, // O
            {{1, 1, 1}, {0, 1, 0}}, // T
            {{1, 1, 0}, {0, 1, 1}}, // S
            {{0, 1, 1}, {1, 1, 0}}, // Z
            {{1, 1, 1}, {1, 0, 0}}, // L
            {{1, 1, 1}, {0, 0, 1}}  // J
    };

    public Tetris1() {
        setPreferredSize(new Dimension(WIDTH * TILE_SIZE, HEIGHT * TILE_SIZE));
        setBackground(Color.BLACK);
        setFocusable(true);
        addKeyListener(this);

        timer = new Timer(DELAY, this);
        timer.start();

        spawnShape();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        drawGrid(g);
        drawShape(g);
    }

    private void drawGrid(Graphics g) {
        for (int y = 0; y < HEIGHT; y++) {
            for (int x = 0; x < WIDTH; x++) {
                if (grid[y][x] != 0) {
                    g.setColor(colors[grid[y][x]]);
                    g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
                }
            }
        }
    }

    private void drawShape(Graphics g) {
        if (currentShape != null) {
            g.setColor(colors[currentColor]);
            for (int y = 0; y < currentShape.length; y++) {
                for (int x = 0; x < currentShape[y].length; x++) {
                    if (currentShape[y][x] == 1) {
                        g.fillRect((currentX + x) * TILE_SIZE, (currentY + y) * TILE_SIZE, TILE_SIZE, TILE_SIZE);
                    }
                }
            }
        }
    }

    private void spawnShape() {
        currentShape = SHAPES[random.nextInt(SHAPES.length)];
        currentX = WIDTH / 2 - currentShape[0].length / 2;
        currentY = 0;
        currentColor = random.nextInt(colors.length - 1) + 1; // 避免使用黑色
    }

    private boolean moveDown() {
        if (!checkCollision(currentX, currentY + 1)) {
            currentY++;
            return true;
        }
        mergeShape();
        clearLines();
        spawnShape();
        if (checkCollision()) {
            gameOver();
        }
        return false;
    }

    private void mergeShape() {
        for (int y = 0; y < currentShape.length; y++) {
            for (int x = 0; x < currentShape[y].length; x++) {
                if (currentShape[y][x] == 1) {
                    grid[currentY + y][currentX + x] = currentColor;
                }
            }
        }
    }

    private void clearLines() {
        for (int y = HEIGHT - 1; y >= 0; y--) {
            boolean full = true;
            for (int x = 0; x < WIDTH; x++) {
                if (grid[y][x] == 0) {
                    full = false;
                    break;
                }
            }
            if (full) {
                for (int yy = y; yy > 0; yy--) {
                    System.arraycopy(grid[yy - 1], 0, grid[yy], 0, WIDTH);
                }
                y++;
            }
        }
    }

    private boolean checkCollision() {
        return checkCollision(currentX, currentY);
    }

    private boolean checkCollision(int x, int y) {
        for (int yy = 0; yy < currentShape.length; yy++) {
            for (int xx = 0; xx < currentShape[yy].length; xx++) {
                if (currentShape[yy][xx] == 1) {
                    int newX = x + xx;
                    int newY = y + yy;
                    if (newX < 0 || newX >= WIDTH || newY >= HEIGHT || (newY >= 0 && grid[newY][newX] != 0)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private void rotateShape() {
        int[][] rotated = new int[currentShape[0].length][currentShape.length];
        for (int y = 0; y < currentShape.length; y++) {
            for (int x = 0; x < currentShape[y].length; x++) {
                rotated[x][currentShape.length - 1 - y] = currentShape[y][x];
            }
        }
        if (!checkCollision(currentX, currentY, rotated)) {
            currentShape = rotated;
        }
    }

    private boolean checkCollision(int x, int y, int[][] shape) {
        for (int yy = 0; yy < shape.length; yy++) {
            for (int xx = 0; xx < shape[yy].length; xx++) {
                if (shape[yy][xx] == 1) {
                    int newX = x + xx;
                    int newY = y + yy;
                    if (newX < 0 || newX >= WIDTH || newY >= HEIGHT || (newY >= 0 && grid[newY][newX] != 0)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private void gameOver() {
        timer.stop();
        JOptionPane.showMessageDialog(this, "Game Over!", "Game Over", JOptionPane.INFORMATION_MESSAGE);
        System.exit(0);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        moveDown();
        repaint();
    }

    @Override
    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_LEFT:
                if (!checkCollision(currentX - 1, currentY)) {
                    currentX--;
                }
                break;
            case KeyEvent.VK_RIGHT:
                if (!checkCollision(currentX + 1, currentY)) {
                    currentX++;
                }
                break;
            case KeyEvent.VK_DOWN:
                moveDown();
                break;
            case KeyEvent.VK_UP:
                rotateShape();
                break;
        }
        repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {}

    @Override
    public void keyTyped(KeyEvent e) {}

    public static void main(String[] args) {
        JFrame frame = new JFrame("Tetris");
        Tetris1 tetris = new Tetris1();
        frame.add(tetris);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}